package com.amt.olcacon.controller.product;

import com.amt.olcacon.db.DerbyConfig;
import com.amt.olcacon.utils.OlcaUtils;
import com.amt.olcacon.vo.GlobalResponse;
import com.amt.olcacon.vo.request.ProductSystemRequest;
import io.micrometer.common.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.openlca.core.DataDir;
import org.openlca.core.database.ProcessDao;
import org.openlca.core.database.ProductSystemDao;
import org.openlca.core.matrix.ProductSystemBuilder;
import org.openlca.core.matrix.cache.MatrixCache;
import org.openlca.core.matrix.linking.LinkingConfig;
import org.openlca.core.matrix.linking.ProviderLinking;
import org.openlca.core.model.*;
import org.openlca.core.model.Process;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * flow api
 *
 * @Author: yangyusheng
 * @Date: 2025/05/28
 */
@Slf4j
@RestController
@RequestMapping("/olca/productsystem")
public class ProductSystemController {

    @PostMapping("/add")
    public GlobalResponse<Long> add(@RequestBody ProductSystemRequest request) {

        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);

        Process process = db.get(Process.class, request.getProcessRefId());
        ProductSystem productSystem = ProductSystem.of(request.getName(), process);

        productSystem.id = request.getId();
        productSystem.refId = request.getRefId();
        productSystem.targetAmount = request.getTargetAmount();
        productSystem.cutoff = request.getCutoff();

        if (StringUtils.isNotBlank(request.getDescription())) {
            productSystem.description = request.getDescription();
        }

        if (StringUtils.isNotBlank(request.getFlowRefId())) {
            Flow flow = db.get(Flow.class, request.getFlowRefId());
            productSystem.referenceExchange = Exchange.of(flow);
            productSystem.targetUnit = flow.getReferenceUnit();
        }
        productSystem.referenceProcess = process;

        if (StringUtils.isNotBlank(request.getFlowPropertyRefId())) {
            productSystem.targetFlowPropertyFactor = FlowPropertyFactor.of(
                    db.get(FlowProperty.class, request.getFlowPropertyRefId()),
                    request.getFlowPropertyFactor()
            );
        }

        // 持久化到数据库
        var dao = new ProductSystemDao(db);
        var result = dao.insert(productSystem);
        db.close();

        return GlobalResponse.of(result.id);
    }

    @PostMapping("/builder")
    public GlobalResponse<Long> Builder(@RequestBody ProductSystemRequest request) {

        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);

        // 加载参考流程（特定UUID对应的生产工艺）
        Process p = new ProcessDao(db).getForRefId(request.getProcessRefId());

        // 配置系统构建参数
        var config = new LinkingConfig()
                .providerLinking(ProviderLinking.PREFER_DEFAULTS)  // 优先使用默认供应商
                .preferredType(ProcessType.UNIT_PROCESS);          // 选择单元流程类型

        // 创建产品系统构建器并执行构建
        ProductSystem system = new ProductSystemBuilder(MatrixCache.createLazy(db), config)
                .build(p);  // 基于参考流程构建完整系统
        system.refId = request.getRefId();
        system.id = request.getId();
        system.name = request.getName();


        // 持久化到数据库
        var dao = new ProductSystemDao(db);
        var result = dao.insert(system);
        db.close();

        return GlobalResponse.of(result.id);
    }

    @Async
    @PostMapping("/asyncBuilder")
    public void asyncBuilder(@RequestBody ProductSystemRequest request) {

        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);

        // 加载参考流程（特定UUID对应的生产工艺）
        Process p = new ProcessDao(db).getForRefId(request.getProcessRefId());

        // 配置系统构建参数
        var config = new LinkingConfig()
                .providerLinking(ProviderLinking.PREFER_DEFAULTS)  // 优先使用默认供应商
                .preferredType(ProcessType.UNIT_PROCESS);          // 选择单元流程类型

        // 创建产品系统构建器并执行构建
        ProductSystem system = new ProductSystemBuilder(MatrixCache.createLazy(db), config)
                .build(p);  // 基于参考流程构建完整系统
        system.refId = request.getRefId();
        system.id = request.getId();
        system.name = request.getName();


        // 持久化到数据库
        var dao = new ProductSystemDao(db);
        dao.insert(system);
        db.close();

    }


    @PostMapping("/update")
    public GlobalResponse<Long> update(@RequestBody ProductSystemRequest request) {

        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);
        var dao = new ProductSystemDao(db);

//        Process process = db.get(Process.class, request.getProcessRefId());
        ProductSystem productSystem = dao.getForId(request.getId());
        productSystem.name = request.getName();

//        productSystem.targetAmount = request.getTargetAmount();
//
//        productSystem.cutoff = request.getCutoff();
//
//        if (StringUtils.isNotBlank(request.getDescription())) {
//            productSystem.description = request.getDescription();
//        }
//
//        if (StringUtils.isNotBlank(request.getFlowRefId())) {
//            Flow flow = db.get(Flow.class, request.getFlowRefId());
//            productSystem.referenceExchange = Exchange.of(flow);
//            productSystem.targetUnit = flow.getReferenceUnit();
//        }
//        productSystem.referenceProcess = process;
//
//        if (StringUtils.isNotBlank(request.getFlowPropertyRefId())) {
//            productSystem.targetFlowPropertyFactor = FlowPropertyFactor.of(
//                    db.get(FlowProperty.class, request.getFlowPropertyRefId()),
//                    request.getFlowPropertyFactor()
//            );
//        }

        // 持久化到数据库
        var result = dao.update(productSystem);
        db.close();

        return GlobalResponse.of(result.id);
    }

    @GetMapping("/delete/{id}")
    public GlobalResponse<String> delete(@PathVariable("id") String id) {

        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);
        new ProductSystemDao(db).delete(Long.parseLong(id));
        db.close();

        return GlobalResponse.success();
    }

    @GetMapping("/get/{refId}")
    public GlobalResponse<ProductSystem> get(@PathVariable("refId") String refId) {

        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);
        var dao = new ProductSystemDao(db);
        ProductSystem productSystem = dao.getForRefId(refId);
        db.close();

        OlcaUtils.cleanNoneFile(productSystem);

        return GlobalResponse.of(productSystem);
    }

    @GetMapping("/getAll")
    public GlobalResponse<List<ProductSystem>> getAll() {

        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);
        var dao = new ProductSystemDao(db);
        List<ProductSystem> productSystems = dao.getAll();
        db.close();

        productSystems.forEach(OlcaUtils::cleanNoneFile);

        return GlobalResponse.of(productSystems);
    }

}
